/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.component.spreadsheet.planning;

import cn.ac.nercis.pes.common.constant.knowledge.TargetApplyClaim;
import cn.ac.nercis.pes.common.constant.project.SpecialType;
import cn.ac.nercis.pes.community.component.spreadsheet.TableSheetView;
import cn.ac.nercis.pes.community.model.vo.project.UnitSpecialTargetVO;
import cn.ac.nercis.pes.community.support.event.EventCallback;
import cn.ac.nercis.pes.model.dto.target.EditSpecialTargetDTO;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.controlsfx.control.spreadsheet.GridBase;
import org.controlsfx.control.spreadsheet.SpreadsheetCell;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 特殊测评指标确认表控件
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public class SpecialTargetSheetView extends TableSheetView<UnitSpecialTargetVO> {
    private final static Integer EMPTY_DATA_COUNT = 3;
    private final static List<String> COLUMNS = List.of("测评指标","测评指标描述","应用要求","特殊指标原因");
    private final static Integer UNIT_TARGET_COLUMN_INDEX = 0;
    private final static Integer EVA_TARGET_COLUMN_INDEX = 1;
    private final static Integer APPLY_COLUMN_INDEX = 2;
    private final static Integer REASONS_COLUMN_INDEX = 3;

    private final ObservableList<String> applyList;

    private EventCallback<Set<String>> onDeleteAction;
    private String systemId;

    public SpecialTargetSheetView(){
        this.getStyleClass().add("pes-sheet-view");
        applyList = FXCollections.observableArrayList(TargetApplyClaim.findApplyClaims());

        var grid = new GridBase(EMPTY_DATA_COUNT, COLUMNS.size());
        grid.setRowHeightCallback(new GridBase.MapBasedRowHeightFactory(heardRowHeight()));
        grid.getColumnHeaders().addAll(COLUMNS);
        setGrid(grid);
        getColumns().get(UNIT_TARGET_COLUMN_INDEX).setPrefWidth(200);
        getColumns().get(EVA_TARGET_COLUMN_INDEX).setPrefWidth(300);
        getColumns().get(APPLY_COLUMN_INDEX).setPrefWidth(100);
        getColumns().get(REASONS_COLUMN_INDEX).setPrefWidth(300);
        //this.setRequiredColumns();
    }

    public void initialize(String systemId,EventCallback<Set<String>> deleteAction){
        this.systemId = systemId;
        this.onDeleteAction = deleteAction;
        this.editModel.set(false);
    }

    @Override
    public void loadContent(List<UnitSpecialTargetVO> data){
        this.editModel.set(false);
        this.sheetData = data;
        this.clearContent();
        for(var dataIndex=0;dataIndex<data.size();dataIndex++){
            this.loadContent(data.get(dataIndex),toSheetRowIndex(dataIndex));
        }
        setGrid(getGrid());
        this.editModel.set(true);
    }

    public List<EditSpecialTargetDTO> getModifyData(){
        List<UnitSpecialTargetVO> data = new ArrayList<>();
        for(var sheetRowIndex=0;sheetRowIndex<this.getGrid().getRows().size();sheetRowIndex++){
            if(this.isEmptyData(sheetRowIndex)){
                continue;
            }
            data.add(getModifyData(sheetRowIndex));
        }
        return data.stream()
                .filter(item-> Objects.nonNull(item) && item.isChange())
                .map(ust->EditSpecialTargetDTO.builder()
                        .id(ust.getId())
                        .systemId(ust.getSystemId())
                        .layerTargetId(ust.getLayerTargetId())
                        .name(ust.getName())
                        .specialType(ust.getSpecialType())
                        .targetDesc(ust.getTargetDesc())
                        .reasons(ust.getReasons())
                        .applyClaim(ust.getKmApplyClaim())
                        .kmTargetId(ust.getKmTargetId())
                        .build())
                .collect(Collectors.toList());
    }

    private UnitSpecialTargetVO getModifyData(Integer sheetRowIndex){
        if(toDataIndex(sheetRowIndex)<0){
            return null;
        }
        var rowData = this.getGrid().getRows().get(sheetRowIndex);
        UnitSpecialTargetVO info;
        if(toDataIndex(sheetRowIndex)<this.sheetData.size()){
            info = this.sheetData.get(toDataIndex(sheetRowIndex));
        } else {
            return null;
        }
        if(info.getSpecialType() == SpecialType.CUSTOM){
            info.setName(StringUtils.trim(rowData.get(UNIT_TARGET_COLUMN_INDEX).getText()));
            info.setTargetDesc(StringUtils.trim(rowData.get(EVA_TARGET_COLUMN_INDEX).getText()));
            info.setKmApplyClaim(rowData.get(APPLY_COLUMN_INDEX).getText());
        }
        info.setReasons(rowData.get(REASONS_COLUMN_INDEX).getText());
        return info;
    }

    @Override
    protected void loadContent(UnitSpecialTargetVO info,Integer sheetRowIndex){
        final ObservableList<SpreadsheetCell> data = FXCollections.observableArrayList();
        AtomicInteger columnIndex = new AtomicInteger(0);
        data.add(getTextAreaCell(sheetRowIndex,columnIndex.getAndIncrement(),info.getName(),
                info.getSpecialType()== SpecialType.CUSTOM));
        data.add(getTextAreaCell(sheetRowIndex,columnIndex.getAndIncrement(),processNewline(info.getTargetDesc()),
                "data-cell-left",info.getSpecialType() == SpecialType.CUSTOM));
        if(info.getSpecialType()==SpecialType.CUSTOM){
            data.add(getComboBoxCell(sheetRowIndex,columnIndex.getAndIncrement(),applyList,info.getKmApplyClaim()));
        }else{
            data.add(getTextAreaCell(sheetRowIndex,columnIndex.getAndIncrement(),info.getKmApplyClaim(),false));
        }
        data.add(getTextAreaCell(sheetRowIndex,columnIndex.getAndIncrement(),info.getReasons(),"data-cell-left",true));
        this.getGrid().getRows().add(data);
        info.resetChange();
    }

    @Override
    protected void clearContent(){
        int endIndex = this.getGrid().getRows().size() -1;
        for(;endIndex>=0;endIndex--){
            this.getGrid().getRows().remove(endIndex);
        }
    }

    @Override
    protected boolean isEmptyData(Integer sheetRowIndex) {
        return toDataIndex(sheetRowIndex) < 0;
    }

    @Override
    protected boolean validate(ObservableList<SpreadsheetCell> rowData) {
        boolean validResult = true;
        if(StringUtils.isBlank(rowData.get(UNIT_TARGET_COLUMN_INDEX).getText())){
            rowData.get(UNIT_TARGET_COLUMN_INDEX).getStyleClass().add(REQUIRED_CELL_STYLE);
            validResult = false;
        }else{
            rowData.get(UNIT_TARGET_COLUMN_INDEX).getStyleClass().remove(REQUIRED_CELL_STYLE);
        }
        return validResult;
    }

    @Override
    protected void clearValidate(ObservableList<SpreadsheetCell> rowData) {
        rowData.get(UNIT_TARGET_COLUMN_INDEX).getStyleClass().remove(REQUIRED_CELL_STYLE);
    }

    @Override
    protected List<String> getDataColumns() {
        return COLUMNS;
    }

    @Override
    protected ObservableList<SpreadsheetCell> generateEmptyDataRow(int rowIndex) {
        return null;
    }

    @Override
    protected void deleteData() {
        if(Objects.nonNull(this.onDeleteAction)){
            var selectIds= this.selectedSheetRowIndex()
                    .stream()
                    .filter(sheetRowIndex->toDataIndex(sheetRowIndex)>=0 && toDataIndex(sheetRowIndex)<this.sheetData.size())
                    .map(sheetRowIndex->this.sheetData.get(toDataIndex(sheetRowIndex)).getId())
                    .collect(Collectors.toSet());
            this.onDeleteAction.action(selectIds);
        }
    }


    protected Map<Integer,Double> heardRowHeight(){
        Map<Integer, Double> rowHeight = new HashMap<>(1);
        IntStream.range(0,20).forEach(number->rowHeight.put(number,80.0));
        return rowHeight;
    }

}